Macro(宏、巨集)在程式語言中是一個使用者自訂的程式語言擴展。在 Lisp 系語言中,macro 的威力相當強大,主要是來自於 Lisp 系語言的「程式碼 - 資料結構同像性」(homoiconic)。這裡簡單紀錄 Clojure 的求值模型。
(defmacro backwards
  [form]
  (reverse form))
(backwards (" backwards" " am" "I" str))
; => "I am backwards"
在 Lisp 系語言中,list 的第一個字必須處理下面的東西,然而,通過 macro,使得特殊形式的語法可以被接受。
Clojure 的求值步驟由兩部組成:
在多數語言中,程式碼首先被轉換成 AST(抽象語法樹)結構。在 Clojure 中,S-expression 本身就是與 AST 等價的結構了。原文提到了篇不錯的文章〈Syntax and Semetics〉。
Reader在 Clojure 中,使用 read-string 讀入程式碼。這個函數接受一個字串參數,然後返回處理後的數據結構。接著可以把數據結構傳給其他函數,也可以用 eval 求取結果。在 Clojure 資料結構中,主要有下列四種形式。
(a b c) 是一個 list 結構str 符號(symbol)結構[1 2] 是一個 vector 結構{:a "b"} 是一個 map 結構這些可以原生轉換。不過,對於 lambda(匿名函數),例如 #(+ 1 %) 這類的,將被 reader macros 轉換為以 Clojure 關鍵字表達的形式。'、#、@ 都是 macro 標誌。
' 會用 quote 展開# 會用 fn 展開@ 會用 deref 展開註解則不展開。
EvaluatorList 的第一個元素會被程序搜尋對應的函數。而不是第一個元素且也不是 list 的其餘元素求值為自身,包括 true、false、{}、:keyword。
接著會查找由 def 根據地一個元素是否有前綴(prefix)在對應的命名空間建立的「符號-值」表查找對應的值(可能是個函數,或者是其他 macro)。順序如下:
fn、if)let 下),越內部的解析優先權越高。另外就是函數調用時,會先對每個元素都完全求值,才做為參數傳遞。